<!--
@description: 大文件切片上传
-->

<template>
  <div>
    <el-upload class="upload-demo" drag multiple :auto-upload="false" :on-change="handleChange">
      <el-icon class="el-icon--upload">
        <upload-filled />
      </el-icon>
      <div class="el-upload__text">
        拖拽到这里或者<em>点击上传</em>
      </div>
    </el-upload>
  </div>
</template>

<script setup lang='js'>
import axios from 'axios';
import SparkMD5 from 'spark-md5';

/* 通过 md5 加密文件 buffer 来生成唯一 hash 值  */
const getFileHash = async (file) => {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();
    fileReader.onload = (e) => {
      const fileHash = SparkMD5.ArrayBuffer.hash(e.target.result);
      resolve(fileHash);
    }
    fileReader.onerror = () => {
      reject('文件读取失败');
    }
    fileReader.readAsArrayBuffer(file);
  })
}

const handleChange = async (files) => {
  const file = files.raw
  const hash = await getFileHash(file)
  // const name = file.name

  /* 分块大小 */
  const chunkSize = 100 * 1024;
  /* 文件切片 */
  const chunks = [];
  let startPos = 0;
  while (startPos < file.size) {
    chunks.push(file.slice(startPos, startPos + chunkSize));
    startPos += chunkSize;
  }

  let chunkSignsArr = new Array(chunks.length).fill(0);
  /* 判断是否已有切片，有切片 (断点续传)，有完整文件 (秒传) */
  const { data } = await axios.get('http://localhost:3000/check-chunks?hash=' + hash + '&name=' + file.name + '&chunkTotal=' + chunks.length);
  if (data.uploadStatus === 'uploaded') {
    console.log('秒传');
    return;
  } else if (data.uploadStatus === 'uploading') {
    chunkSignsArr = [...data.chunkSignsArr]
  }

  /* 切片上传 */
  const tasks = [];
  chunks.map((chunk, index) => {
    if (chunkSignsArr[index] === 0) {
      const data = new FormData();
      data.set('name', hash + '_' + index)
      data.set('hash', hash)
      data.append('files', chunk);
      tasks.push(axios.post('http://localhost:3000/upload', data, {
        onUploadProgress: (progressEvent) => {
          console.log(`${index}上传进度:`, (progressEvent.loaded / progressEvent.total * 100).toFixed(2) + '%');
        }
      }));
    }
  })
  await Promise.all(tasks);
  /* 合并切片 */
  axios.get('http://localhost:3000/merge?name=' + file.name + '&hash=' + hash);
}

</script>